package server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import util.MyClassLoad;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Bootstrap {

    /**
     * 监听的端口
     */
    public int port = 8080;

    //private Map<String, HttpServlet> servletMap = new HashMap<>();

    // 扫描磁盘上的项目后 存在 web.xml配置文件的项目 路径
    // key : 项目名称
    // value : 磁盘上的绝对路径
    private Map<String, String> servletPath = new HashMap<>();

    private Mapper mapper = new Mapper();


    // 启动线程池
    public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            10,
            20,
            20,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(50));

    /**
     * 程序初始化的 内容
     */
    public void start() throws IOException {

        // 扫描webapps目录下的所有项目
        scanPackage();

        if(servletPath.isEmpty()){
            System.out.println("========> start error : no servlet");
            return;
        }
        // 加载 配置文件
        for(Map.Entry<String, String> entry : servletPath.entrySet()){
            loadResource(entry);
        }


        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("========> serverSocket start on port：" + port);

        /**
         * 1.0版本
         */
        /*while (true){
            Socket socket = serverSocket.accept();
            OutputStream outputStream = socket.getOutputStream();
            String result = "hello minicat";
            String response = HttpProtocolUtil.getHttpHead200(result.length()) + result;
            outputStream.write(response.getBytes());
            socket.close();

        }*/

        /**
         * 2.0 版本  实现静态资源的访问
         */
        /*while (true){
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();
            // 封装成的输入对象
            Request request = new Request(inputStream);
            // 封装成的输出对象
            Response response = new Response(socket.getOutputStream());
            response.outputHtml(request.getUrl());
            socket.close();
        }*/

        /**
         * 3.0 版本  实现动态资源的访问
         */
        /*while (true){
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();
            // 封装成的输入对象
            Request request = new Request(inputStream);
            // 封装成的输出对象
            Response response = new Response(socket.getOutputStream());

            // 动、静资源 的访问
            if(servletMap.get(request.getUrl()) == null){
                response.outputHtml(request.getUrl());
            } else {
                HttpServlet httpServlet = servletMap.get(request.getUrl());
                try {
                    httpServlet.service(request, response);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            socket.close();
        }*/

        /**
         * 4.0 版本  加入多线程改造
         */
        /*while (true){
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket, servletMap);
            threadPoolExecutor.execute(requestProcessor);
        }*/

        /**
         * 5.0 版本  多部署
         */
        while (true) {
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket, mapper);
            threadPoolExecutor.execute(requestProcessor);
        }
    }

    private void scanPackage() {
        String dirPath = System.getProperty("user.dir"); // 路径
        String path = dirPath.replace("\\", "/") +
                "/Minicat/src/main/webapps/";

        File f = new File(path);
        if (!f.exists()) {
            System.out.println(path + " not exists");
            return;
        }

        File fa[] = f.listFiles();
        for (int i = 0; i < fa.length; i++) {
            File fs = fa[i];
            String fileName = fs.getName();
            String contextUrl = "/WEB-INF/web.xml";
            String p = path + fileName + contextUrl;
            File file = new File(p);
            if(file.exists()){
                servletPath.put(fileName, p);
            }
        }
    }

    private void loadResource(Map.Entry<String, String> entry) {
        // 项目名称 ： web_demo_test1
        String key = entry.getKey();

        // 项目中 所有servlet存放的位置
        Mapper.MappedContext mappedContext = new Mapper.MappedContext();
        mappedContext.setContextUrl(key);

        ClassLoader classLoader = new MyClassLoad(key);

        // 加载配置文件
        try {
            InputStream resourceAsStream = new FileInputStream(new File(entry.getValue()));
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(resourceAsStream);
            // 查找<servlet>
            List<Element> list = document.selectNodes("//servlet");
            for (Element element : list) {
                //<servlet-name>myservlet</servlet-name>
                Element servletNameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletNameElement.getStringValue();

                //<servlet-class>servlet.TestServlet</servlet-class>
                Element servletClassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletClassElement.getStringValue();

                // 根据 servletName 找到  url-pattern
                Element servletMapping =
                        (Element) document.selectSingleNode("web-app/servlet-mapping[servlet-name='" + servletName + "']");
                Element urlPatternElement = (Element) servletMapping.selectSingleNode("url-pattern");
                String urlPattern = urlPatternElement.getStringValue();

                Mapper.MappedWrapper mappedWrapper = new Mapper.MappedWrapper();
                mappedWrapper.setWrapperUrl(urlPattern);
                mappedWrapper.setServletClass(servletClass);
                HttpServlet instance =(HttpServlet)classLoader.loadClass(servletClass).newInstance();
                mappedWrapper.setHttpServlet(instance);

                mappedContext.getWrapperList().add(mappedWrapper);
                //servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).newInstance());
            }

            mapper.putMappedContext(key, mappedContext);

        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e){
            e.printStackTrace();
        }

    }


    /**
     * 程序入口
     *
     * @param args
     */
    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }
}
